package cn.kgc.service.impl;

import cn.kgc.client.RestDmImageClient;
import cn.kgc.client.RestDmUserClient;
import cn.kgc.exception.UserErrorCode;
import cn.kgc.pojo.DmImage;
import cn.kgc.pojo.DmUser;

import cn.kgc.service.UserService;
import cn.kgc.util.RedisUtil;
import cn.kgc.utils.*;
import cn.kgc.vo.DmUserVO;
import cn.kgc.vo.TokenVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutionException;

@Service
public class UserServiceImpl implements UserService {


    @Autowired
    RestDmUserClient restDmUserClient;

    @Autowired
    RestDmImageClient restDmImageClient;

    @Autowired
    SmsUtils smsUtils;

    @Autowired
    RedisUtil redisUtil;

    /**
     * 思路
     * 业务实现逻辑
     * 登录的思路
     * 1.用户名和密码是否正确，根据用户名（phone）获取用户对象，判断密码是否正确,User
     * 2.用户名，密码校验成功，就可以获取一个userVo,把User(pojo)导入到UserVo,组装数据
     * 3.获取用户头像信息，组装到userVo中
     * 4.生成一个token,是一个字符串，令牌
     * 5.把token放到redis中储存起来
     * 6.做一个tokenVo,封装token,生成时间，过期时间
     * 7.tokenvo和userVo 封装Object[]数组的方式返回
     *
     * @param phone
     * @param secrtPassword
     * @return
     */
    @Override
    public Object[] queryLogin(String phone, String secrtPassword) throws Exception {
//       * 1.用户名和密码是否正确，根据用户名（phone）获取用户对象，判断密码是否正确,User
        java.util.Map map =new HashMap();
        map.put("phone",phone);
        List<DmUser> listByMap= restDmUserClient.getDmUserListByMap(map);
        if(listByMap==null||listByMap.size()==0){
            throw  new BaseException(UserErrorCode.User_No_EXIST);
        }
        DmUser dmUser=listByMap.get(0);
        if(EmptyUtils.isEmpty(secrtPassword)||!(dmUser.getPassword().equals(secrtPassword))){
            throw new BaseException(UserErrorCode.User_ERROR_PASSWORD);
        }

        //  2.用户名，密码校验成功，就可以获取一个userVo,把User(pojo)导入到UserVo,组装数据
        DmUserVO dmUserVO = new DmUserVO();
        BeanUtils.copyProperties(dmUser,dmUserVO);
        dmUserVO.setUserId(dmUser.getId());

//                * 3.获取用户头像信息，组装到userVo中
        List<DmImage> dmImage_defaultImage = restDmImageClient.getDmImage_DefaultImage(dmUser.getId(), Constants.Image.ImageType.normal, Constants.Image.ImageCategory.user);
        dmUserVO.setImageId(dmImage_defaultImage.get(0).getId());
        dmUserVO.setImgUrl(dmImage_defaultImage.get(0).getImgUrl());


//                * 4.生成一个token,是一个字符串，令牌  (唯一性)
        String token= generateToken(phone);


//                * 5.把token放到redis中储存起来
        saveToken(token,dmUserVO);
//                * 6.做一个tokenVo,封装token,生成时间，过期时间
        TokenVO tokenVO =new TokenVO();

        Date date =new Date();
        tokenVO.setToken(token);
        tokenVO.setExpTime(date.getTime()+Constants.Redis_Expire.SESSION_TIMEOUT*1000);
        tokenVO.setGenTime(date.getTime());

//                * 7.tokenvo和userVo 封装Object[]数组的方式返回
        return new Object[]{dmUserVO,tokenVO};
    }

    @Override
    public TokenVO replaceToken(String token) throws BaseException {
        //token置换是有条件，有时间要求的，token生成的时间必须是大于1.5h，也就是说旧的token在redis中剩余的时间小于30分钟，就允许续约。否则不允许置换。
        //1.判断token是否是置换期，布置置换期不需要置换
        long expire = redisUtil.getExpire(token);
        if(expire==-2){
            throw new BaseException(UserErrorCode.USER_NOT_LOGIN);
        }

        if(expire>Constants.Redis_Expire.REPLACEABLE_TIME_RANGE){
            throw new BaseException(UserErrorCode.TOKEN_NOT_TIMEOUT);
        }


        //2.获取token的用户的信息
        DmUserVO dmUserVO= (DmUserVO) redisUtil.get(token);

        //3.生成key( "userToken:phone---zhzbin@163.com")，生成新的token,放到redis中
        //4.生成token  用户信息， 放到redis中
        String newToken = this.generateToken(dmUserVO.getPhone());
        this.saveToken(newToken,dmUserVO);

        //5.新老交替，老token延时死亡，给2分钟,给新的token有时间返回到浏览器放到浏览器的localStorage(中)
        redisUtil.expire(token,Constants.Redis_Expire.REPLACEMENT_DELAY);

        //6.返回tokenvo
        Date date =new Date();
        TokenVO tokenVO = new TokenVO();
        tokenVO.setToken(newToken);
        tokenVO.setExpTime(date.getTime()+Constants.Redis_Expire.SESSION_TIMEOUT*1000);
        tokenVO.setGenTime(date.getTime());
        return tokenVO;
    }

    @Override
    public void sendLoginCode(String phone) throws BaseException, ExecutionException, InterruptedException {
        //  手机验证码发送成功，验证码5分钟有效
        //  手机验证码一分钟之内只发送一条短信
        //  从redis中获取phone的失效时间，1分钟，如果存在这个key,说明在1分钟内，不允许重新发送code
        //  假如手机号，还在redis中，且剩余时间4:分30秒   >4分钟
        if (redisUtil.getExpire(Constants.USER_LOGIN_CODE+phone)>Constants.Redis_Expire.LOGIN_CODE_DELAY-Constants.Redis_Expire.DEFAULT_EXPIRE) {
            //不能再次发送短信，因为1分钟后才能重新发送验证码
            throw  new BaseException(UserErrorCode.USER_CODE_EXIST);
        }
        //2.redis中没有这个phone的验证码，或者距离上一次 发送验证码已经有1分多钟，是可以发送验证码的
        //生成随机数
        Double code=(1000+Math.random()*9000);

        String s = smsUtils.sendSmsCode(phone, Constants.SMS_Template.LOGIN_TEMPLATE, "{code:"+code.intValue() +"}");

        if(s!=null&&s.equals("OK")) {
            //3.验证码放到redis中，并且给过期时间5分钟
            redisUtil.set(Constants.USER_LOGIN_CODE + phone, code.intValue(), Constants.Redis_Expire.LOGIN_CODE_DELAY);
        }
    }

    @Override
    public Object[] checkPhoneLoginCode(String phone, String vcode) throws Exception {

        //1.redis phone获取验证码
       Integer codevalue = ((Integer) redisUtil.get(Constants.USER_LOGIN_CODE + phone));

        //2.不存在验证码，或者验证码不匹配vcode,抛异常
        if(codevalue==null){
            throw new BaseException(UserErrorCode.INVLIDE_CODE);
        }

        String code=codevalue.toString();
        if(!code.equals(vcode)){
            throw new BaseException(UserErrorCode.ERROR_LOGIN_CODE);
        }

        //3.通过手机号码查询用户信息,user，如果没有用户信息，就是第一次登录
            Map map=new HashMap<String,Object>();
            map.put("phone",phone);
            List dmUserListByMap = restDmUserClient.getDmUserListByMap(map);

        //4.第一次登录，则需要插入phone放入到数据库的user表（注册）,new 一个user,封装phone

            DmUser dmUser=null;
            if(dmUserListByMap.size()==0){
                dmUser= new DmUser();
                dmUser.setPhone(phone);
                dmUser.setCreatedTime(new Date());
                Integer id = restDmUserClient.qdtxAddDmUser(dmUser);
                dmUser.setId(new Long(id));
            }else{
                dmUser= (DmUser) dmUserListByMap.get(0);
            }

        //5.生成token放到redis,返回tokenvo
        String token= generateToken(phone);

        DmUserVO dmUserVO = new DmUserVO();
        BeanUtils.copyProperties(dmUser,dmUserVO);
        dmUserVO.setUserId(dmUser.getId());

//                * 3.获取用户头像信息，组装到userVo中
        List<DmImage> dmImage_defaultImage = restDmImageClient.getDmImage_DefaultImage(dmUser.getId(), Constants.Image.ImageType.normal, Constants.Image.ImageCategory.user);
        dmUserVO.setImageId(dmImage_defaultImage.get(0).getId());
        dmUserVO.setImgUrl(dmImage_defaultImage.get(0).getImgUrl());



        saveToken(token,dmUserVO);
//                * 6.做一个tokenVo,封装token,生成时间，过期时间
        TokenVO tokenVO =new TokenVO();

        Date date =new Date();
        tokenVO.setToken(token);
        tokenVO.setExpTime(date.getTime()+Constants.Redis_Expire.SESSION_TIMEOUT*1000);
        tokenVO.setGenTime(date.getTime());

//                * 7.tokenvo和userVo 封装Object[]数组的方式返回
        return new Object[]{dmUserVO,tokenVO};
    }

    public void saveToken(String token, DmUserVO dmUserVO) {
        //1.token放到redis里面存储， 将来登录校验验证  key(?)  value（token）  userToken:zhuweijun
        String key =dmUserVO.getPhone()!=null?Constants.USER_TOKEN_PREFIX+dmUserVO.getPhone():Constants.USER_TOKEN_PREFIX+dmUserVO.getWxUserId();
        if (!EmptyUtils.isEmpty(redisUtil.get(key))) {
            redisUtil.del(key);
        }
        redisUtil.set(key,token,Constants.Redis_Expire.SESSION_TIMEOUT);

        //2.dmUserVo存到redis中， 将来根据token获取用户信息 key(token) value(userVo)
        redisUtil.set(token, dmUserVO,Constants.Redis_Expire.SESSION_TIMEOUT);
    }

    @Override
    public DmUserVO getUserVoByToken(String token) {
        //2.获取token的用户的信息
        DmUserVO dmUserVO= (DmUserVO) redisUtil.get(token);
        return  dmUserVO;
    }

    public String generateToken(String wxid_phone) {
        //唯一的
        StringBuffer stringBuffer =new StringBuffer();

        //时间戳，phone,随机数---->唯一
        stringBuffer.append("token-pc-");
        stringBuffer.append(MD5.getMd5(wxid_phone,8));
        stringBuffer.append("-");
        stringBuffer.append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        stringBuffer.append("-");
        stringBuffer.append(UUID.randomUUID().toString().substring(0,6));
        return stringBuffer.toString();
    }


}
